package com.qf.controller;

import com.alibaba.fastjson.JSONObject;
import com.hazelcast.util.StringUtil;
import com.qf.captcha.CaptchaCodeManager;
import com.qf.pojo.DtsAdmin;
import com.qf.service.DtsAdminService;
import com.qf.service.DtsPermissionService;
import com.qf.service.DtsRoleService;
import com.qf.util.Base64;
import com.qf.util.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Cc
 * @version 1.0
 */

@CrossOrigin
@RestController
@RequestMapping("/admin/auth")
public class AdminAuthController {

    private final org.slf4j.Logger logger = LoggerFactory.getLogger(AdminAuthController.class);

    @Autowired
    private DtsRoleService dtsRoleService;

    @Autowired
    private DtsPermissionService dtsPermissionService;

    @Autowired
    private DtsAdminService dtsAdminService;

    @Autowired
    private ApplicationContext context;

    private HashMap<String, String> permissionsMap = null;


    /**
     * 生成验证码
     *
     * @return
     * @throws IOException
     */
    @GetMapping("/captchaImage")
    public Object captchaImage() throws IOException {
        // 1. 指定验证码的位数
        String text = VerifyCodeUtils.generateVerifyCode(1);

        // 2. 生成一个验证码

        // 验证码的宽度
        int w = 111;
        // 验证码的高度
        int h = 48;
        // 3. 真的生成一个验证码
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        VerifyCodeUtils.outputImage(w, h, bos, text);

        // 4. 将生成的验证码转换为base64编码,方便咱们传输给前端.
        String captcha = Base64.encode(bos.toByteArray());

        // 5. 生成UUID
        String uuid = UUID.randomUUID().toString();

        // 把生成的验证存储到缓存当中;
        // 如果成功了,则把存储的uuid和验证码返回给前端,如果失败了,返回前端错误信息
        if (!CaptchaCodeManager.addToCache(uuid, text, 10)) {
            return ResponseUtil.serious();
        }
        try {
            Map<String, Object> result = new HashMap<>();
            result.put("img", captcha);
            result.put("uuid", uuid);
            return ResponseUtil.ok(result);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseUtil.serious();
        } finally {
            if (bos != null) {
                bos.close();
            }
        }


    }

    /**
     * 登录方法   登录的时候使用 shiro权限验证登录
     * <p>
     * {
     * "code": "66e8",
     * "password": "123456",
     * "username": "qianfeng",
     * "uuid": "cab317c6-1bf1-436d-96ac-fda9f8d37dde"
     * }
     *
     * @return
     */
    @PostMapping("/login")
    public Object login(@RequestBody String body) {
        logger.info("【请求开始】系统管理->用户登录,请求参数:body:{}", body);
        //1.获取到前端输入的用户名和密码  从 json 转换成 string 类型
        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");
        String code = JacksonUtil.parseString(body, "code");
        String uuid = JacksonUtil.parseString(body, "uuid");

        //2.参数的非空校验
        if (StringUtil.isNullOrEmpty(username) || StringUtil.isNullOrEmpty(password) || StringUtil.isNullOrEmpty(code) || StringUtil.isNullOrEmpty(uuid)) {
            logger.info("[登录模块] ---> 用户登录失败了, 用户名称密码验证码为空");
            return ResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_NAME.code(), AdminResponseCode.ADMIN_INVALID_NAME.desc());
        }
        //验证码的校验
        String cachedCaptcha = CaptchaCodeManager.getCachedCaptcha(uuid);
        if (!cachedCaptcha.equalsIgnoreCase(code)) {
            logger.error("「管理模块」用户登录, 验证码不对");
            return ResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_NAME.code(), AdminResponseCode.ADMIN_INVALID_NAME.desc());
        }

        // 获取 subject对象 使用shiro的login方法登录
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
        } catch (UnknownAccountException e) {//这个异常是账号错误
            logger.error("「登录模块」---> 用户登录, 当前 {} 不存在", username);
            return ResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_ACCOUNT_OR_PASSWORD.code(),
                    AdminResponseCode.ADMIN_INVALID_ACCOUNT_OR_PASSWORD.desc());
        } catch (IncorrectCredentialsException e) {//这个异常是密码错误
            logger.error("「登录模块」---> 用户登录, 当前 {} 不存在", username);
            return ResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_ACCOUNT_OR_PASSWORD.code(),
                    AdminResponseCode.ADMIN_INVALID_ACCOUNT_OR_PASSWORD.desc());
        } catch (AuthenticationException e) { //一些其他的异常
            logger.error("「登录模块」---> 登录时发生异常");
            return ResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_AUTH.code(),
                    AdminResponseCode.ADMIN_INVALID_AUTH.desc());
        }
        return ResponseUtil.ok(subject.getSession().getId());

    }

    /**
     * 用户登录后进入此方法获取用户名, 角色, 权限信息
     *
     * @return
     */
//    @RequiresAuthentication
    @GetMapping("/info")
    public Object info() {
        Subject subject = SecurityUtils.getSubject();
        String username = (String) subject.getPrincipal();
        logger.info("「管理模块」- 获取授权信息的用户名称是: {}", username);
        Map<String, Object> map = new HashMap<>();
        map.put("name", username);

        List<DtsAdmin> dtsAdminList = dtsAdminService.findAdmin(username);
        Assert.state(dtsAdminList.size() < 2, "不止一个用户哦");

        //判断是否已经查到了数据
        if (dtsAdminList.size() == 0) {
            logger.error("「用户模块」用户登录认证 :当前没有找到 {} 的用户.", username);
            throw new AuthenticationException("认证失败,没有找到用户");
        }

        //找到当前验证的用户
        DtsAdmin admin = dtsAdminList.get(0);
        map.put("avatar", admin.getAvatar());

        // 获取用户名称对应的角色的ids字段
        Integer[] ids = admin.getRoleIds();
        logger.info("「管理模块」用户登录 -----> ids: {}", Arrays.toString(ids));

        // 根据ids去dts_role表当中查询出对应的角色名称
        Set<String> roleName = dtsRoleService.queryByIds(ids);
        logger.info("「管理模块」获取的角色名称 ----->   role name: {}", roleName);
        map.put("role", roleName.toArray());


        // 通过username查询出来的该名字对应的权限集合, 在dts_permission给.
        /**
         * admin:order:list
         * admin:goods:update
         * admin:groupon:read
         * admin:order:listShip
         */
        Set<String> permissionList = dtsPermissionService.queryByRoleIds(ids);
        map.put("perms", toApi(permissionList));
        // 将 admin:groupon:read 转换成 ---->  admin/groupon/read
        // admin:comment:list
        // get admin/comment/list
        return ResponseUtil.ok(map);
    }


    /**
     * 将权限字符串集合转换成api形式的权限集合
     *
     * @param
     * @return
     */
    private Collection<String> toApi(Set<String> perms) {
        //1:指定 Controller注解所在的包
        String basicPackage = "com.qf.controller";
        //2:校验权限中是否包含最高权限 *
        if (!CollectionUtils.isEmpty(perms)) {
            if (perms.contains("*")) {
                return Arrays.asList("*");
            }
            //3:获取当前项目中所有权限与URI
            List<Permission> permissionList = PermissionUtil.listPermission(context, basicPackage);
            //4:返回当前用户所拥有的URI
            if (!CollectionUtils.isEmpty(permissionList)) {
                return permissionList.stream().filter(permission -> {
                    String perm = permission.getRequiresPermissions().value()[0];
                    if (perms.contains(perm)) {
                        return true;
                    } else {
                        return false;
                    }
                }).map(Permission::getApi).collect(Collectors.toList());
            }
        }
        return Arrays.asList("");
    }


    /*
     * 用户注销
     */
    @RequiresAuthentication
    @PostMapping("/logout")
    public Object login() {
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.logout();

        logger.info("【请求结束】系统管理->用户注销,响应结果:{}", JSONObject.toJSONString(currentUser.getSession().getId()));
        return ResponseUtil.ok();
    }


    /**
     * 登录成功请求首页的接口
     *
     * @return
     */
    @GetMapping("/index")
    public Object pageIndex() {
        return ResponseUtil.ok();
    }


}
